package ru.spb.osll.myfit.client.view;

import java.util.LinkedList;
import java.util.List;

import com.google.gwt.regexp.shared.MatchResult;
import com.google.gwt.regexp.shared.RegExp;
import ru.spb.osll.myfit.client.dialog.ConfirmationDialogListener;
import ru.spb.osll.myfit.client.dialog.DialogEventListener;
import ru.spb.osll.myfit.client.dialog.ErrorDialog;
import ru.spb.osll.myfit.client.dialog.RunSuiteDialog;
import ru.spb.osll.myfit.client.dialog.SaveWithErrorsDialog;
import ru.spb.osll.myfit.client.event.PageButtonEvent;
import ru.spb.osll.myfit.client.event.PageEvent;
import ru.spb.osll.myfit.client.log.RemoteLogger;
import ru.spb.osll.myfit.client.manager.PageElementManager;
import ru.spb.osll.myfit.client.manager.PageExecutingManager;
import ru.spb.osll.myfit.client.service.FitService;
import ru.spb.osll.myfit.client.service.FitServiceAsync;
import ru.spb.osll.myfit.client.widget.GWTWidgetFactory;
import ru.spb.osll.myfit.client.widget.PageButtonEventListener;
import ru.spb.osll.myfit.client.widget.PageExecutingListener;
import ru.spb.osll.myfit.client.widget.PageWidget;
import ru.spb.osll.myfit.common.Page;
import ru.spb.osll.myfit.common.PageExecutingResult;
import ru.spb.osll.myfit.common.VerificationResult;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;

public class MyFitViewController implements IViewController {

  /**
   * Create a remote service proxy to talk to the server-side Fit service.
   */
  private final FitServiceAsync m_fitService = GWT.create(FitService.class);

  private PageExecutingManager m_executingManager = new PageExecutingManager();

  private SaveWithErrorsDialog m_saveDialog = new SaveWithErrorsDialog();

  private ErrorDialog m_errorDialog = new ErrorDialog();

  private DialogEventListener m_runSuiteDialogListener;
  private RunSuiteDialog m_runSuiteDialog;

  private MyFitView m_MyFitView;

  public MyFitViewController() {
    m_runSuiteDialogListener = new DialogEventListener() {
      @Override
      public void onOK(String input, PageEvent sourceEvent) {
        List<PageExecutingListener> listeners = new LinkedList<PageExecutingListener>();
        listeners.add(new PageExecutingListener() {
          private boolean m_windowOpened = false;

          @Override
          public void processPageExecutingResult(PageExecutingResult result) {
            if (!m_windowOpened) {
              Window.open("test_result?id=" + result.getId(), "_blank", "");
              m_windowOpened = true;
            }
          }

          @Override
          public void finish() {
          }
        });

        m_executingManager.executeTestPage(listeners, m_MyFitView.getPagePath(), input);
      }
    };
    m_runSuiteDialog = new RunSuiteDialog(m_runSuiteDialogListener);
  }

  @Override
  public IView getView(String address) {
    RegExp re = RegExp.compile("([a-zA-Z0-9_.]*)");
    String pageName = address;
    if(re.test(address)){
      MatchResult m = re.exec(address);
      if (m.getGroupCount() > 0) {
        pageName = m.getGroup(0);
      }
    }
    PageWidget pageWidget = new PageWidget(new GWTWidgetFactory(), pageName);
    PageElementManager pageElementManager = new PageElementManager();
    pageWidget.addPageEventListener(pageElementManager);
    m_MyFitView = new MyFitView(pageWidget, createButtonEventListener());
    loadPage(pageName);
    return m_MyFitView;
  }

  private void loadPage(final String address) {

    m_fitService.loadPage(address, new AsyncCallback<VerificationResult>() {

      public void onFailure(Throwable caught) {
        m_errorDialog.setMessage(caught);
        m_errorDialog.center();
      }

      public void onSuccess(VerificationResult pageVerificationResult) {
        if (pageVerificationResult != null) {
          reloadPage(pageVerificationResult);
        }
      }
    });
  }

  private void reloadPage(VerificationResult pageVerificationResult) {
    boolean hasError = pageVerificationResult.hasError();
    m_MyFitView.setVerifierResult(hasError);
    Page page = pageVerificationResult.getPage();
    m_MyFitView.reloadPage(page);
  }

  private PageButtonEventListener createButtonEventListener() {
    PageButtonEventListener listener = new PageButtonEventListener() {

      @Override
      public void actionPerformed(PageButtonEvent event) {
        switch (event.getType()) {
          case SAVE_PAGE:
            verifyAndSaveTestPage();
            break;
          case TEST_PAGE:
            executeTestPage();
            break;
          case RUN_SUITE:
            runSuite();
            break;
          case REFRESH:
            com.google.gwt.user.client.Window.Location.reload();
            break;
          case VERIFY_PAGE:
            verifyTestPage();
            break;
          case RELOAD_TABLE_TEMPLATES: {
            reloadTemplates();
            break;
          }
          case RESULTS_FOR_PAGE: {
            Window.open(ViewConstants.TEST_TABLE_ADDRESS + "?test=" + m_MyFitView.getPagePath(), "", "");
            break;
          }
          default:
            break;
        }
      }
    };
    return listener;
  }

  public void savePage() {
    m_fitService.savePage(m_MyFitView.getPagePath(), m_MyFitView.getPage(), new AsyncCallback<Void>() {
      public void onFailure(final Throwable caught) {
        m_errorDialog.setMessage(caught);
        m_errorDialog.center();
      }

      public void onSuccess(final Void result) {
      }
    });
  }

  private void verifyTestPage() {
    m_fitService.verifyPage(m_MyFitView.getPage(), new AsyncCallback<VerificationResult>() {

      public void onFailure(Throwable caught) {
        m_errorDialog.setMessage(caught);
        m_errorDialog.center();
      }

      public void onSuccess(VerificationResult pageVerificationResult) {
        reloadPage(pageVerificationResult);
      }
    });
  }

  private void verifyAndSaveTestPage() {
    m_fitService.verifyPage(m_MyFitView.getPage(), new AsyncCallback<VerificationResult>() {

      public void onFailure(Throwable caught) {
        m_errorDialog.setMessage(caught);
        m_errorDialog.center();
      }

      public void onSuccess(VerificationResult pageVerificationResult) {
        boolean hasError = pageVerificationResult.hasError();
        reloadPage(pageVerificationResult);

        if (hasError) {
          m_saveDialog.setListener(new ConfirmationDialogListener() {
            @Override
            public void confirmed() {
              savePage();
            }

            @Override
            public void cancelled() {
            }

          });

          m_saveDialog.center();
          m_saveDialog.show();

        } else {
          savePage();
        }
      }
    });
  }

  private void executeTestPage() {
    m_runSuiteDialogListener.onOK("", null);
  }

  private void runSuite() {
    m_runSuiteDialog.center();
    m_runSuiteDialog.show();
  }

  private void reloadTemplates() {
    m_fitService.reloadTemplates(new AsyncCallback<Void>() {
      public void onFailure(Throwable caught) {
        RemoteLogger.error("Error reloading fixture list");
      }

      public void onSuccess(Void obj) {
        m_MyFitView.reloadTemplates();
        com.google.gwt.user.client.Window.Location.reload();
      }
    });
  }
}